package com.xj.spring.framework.context;

import com.xj.spring.framework.annotation.GPAutowired;
import com.xj.spring.framework.annotation.GPController;
import com.xj.spring.framework.annotation.GPService;
import com.xj.spring.framework.beans.MyBeanWrapper;
import com.xj.spring.framework.beans.config.MyBeanDefinition;
import com.xj.spring.framework.beans.suppoort.MyBeanDefinitionReader;
import com.xj.spring.framework.beans.suppoort.MyDefaultListableBeanFactory;
import com.xj.spring.framework.core.MyBeanFactory;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author xujiang
 * @date 2021/5/6 23:09
 **/
public class MyApplicationContext implements MyBeanFactory {

    private MyDefaultListableBeanFactory registry = new MyDefaultListableBeanFactory();

    // 循环依赖的标识
    private Set<String> singletonsCurrentlyInCreation = new HashSet<String>();
    // 一级缓存
    private Map<String, Object> singletonObjects = new HashMap<String, Object>();
    // 二级缓存
    private Map<String, Object> earlySingletonObjects = new HashMap<String, Object>();

    // 三级缓存 （终极缓存）
    private Map<String, MyBeanWrapper> factoryBeanInstanceCache= new HashMap<String, MyBeanWrapper>();

    private Map<String, Object> factoryBeanObjectCache = new HashMap<String, Object>();

    private MyBeanDefinitionReader reader;

    public MyApplicationContext(String ... configLocations) {
        // 1、 加载配置文件
        reader = new MyBeanDefinitionReader(configLocations);

        try {
            // 2、 解析配置文件，将所有的配置信息封装成BeanDefinition对象
            List<MyBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();

            // 3、所有的配置信息缓存起来
            this.registry.doRegistBeanDefinition(beanDefinitions);

            // 4、加载非延时加载的所有Bean
            doLoadInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }



    }

    private void doLoadInstance() {
        // 循环调用getBean()方法
        for (Map.Entry<String, MyBeanDefinition> entry : this.registry.beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            if (!entry.getValue().isLazyInit()) {
                getBean(beanName);
            }

        }
    }

    @Override
    public Object getBean(Class beanClass) {
        return getBean(beanClass.getName());
    }

    /**
     * 从Ioc容器中获得一个Bean对象
     * @param beanName
     * @return
     */
    @Override
    public Object getBean(String beanName) {
        // 1、 先拿到beanDefinition配置信息
        MyBeanDefinition beanDefinition = registry.beanDefinitionMap.get(beanName);

        // entry
        Object singleton = getSingleton(beanName, beanDefinition);
        if (singleton!=null) {return singleton;}

        // 标记正在创建的bean
        if (!singletonsCurrentlyInCreation.contains(beanName)) {
            singletonsCurrentlyInCreation.add(beanName);
        }

        // 2、反射实例化对象
        Object instance = instantiateBean(beanName, beanDefinition);

        // 存入一级缓存
        this.singletonObjects.put(beanName, instance);

        // 3、将返回的Bean对象封装成BeanWrapper
        MyBeanWrapper beanWrapper = new MyBeanWrapper(instance);


        // 4、执行依赖注入
        populateBean(beanName, beanDefinition, beanWrapper);

        // 5、保存到IOC容器中
        this.factoryBeanInstanceCache.put(beanName, beanWrapper);
        return beanWrapper.getWrappedInstance();
    }

    private Object getSingleton(String beanName, MyBeanDefinition beanDefinition) {
        // 先去一级缓存里拿
        Object bean = singletonObjects.get(beanName);
        // 如果一级缓存中没有，但是又有创建标识，说明就是循环依赖
        if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
            bean = earlySingletonObjects.get(beanName);
            // 如果二级缓存没有就去三级缓存中拿
            if (bean == null) {
                Object object = instantiateBean(beanName, beanDefinition);
                // 将创建出来的对象放到二级缓存中
                earlySingletonObjects.put(beanName, object);
            }
        }
        return null;
    }


    private void populateBean(String beanName, MyBeanDefinition beanDefinition, MyBeanWrapper beanWrapper) {

        Object instance = beanWrapper.getWrappedInstance();
        Class<?> clazz = beanWrapper.getWrappedClass();
        if (!(clazz.isAnnotationPresent(GPController.class) || clazz.isAnnotationPresent(GPService.class))) {
            return;
        }

        //忽略字段的修饰符，不管你是 private / protected / public / default
        for (Field field : clazz.getDeclaredFields()) {
            if(!field.isAnnotationPresent(GPAutowired.class)){ continue; }

            GPAutowired autowired = field.getAnnotation(GPAutowired.class);
            String autowiredBeanName = autowired.value().trim();
            if("".equals(autowiredBeanName)){
                autowiredBeanName = field.getType().getName();
            }

            //代码在反射面前，那就是裸奔
            //强制访问，强吻
            field.setAccessible(true);

            try {
                if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) {return;}
                //相当于 demoAction.demoService = ioc.get("com.gupaoedu.demo.service.IDemoService");
                field.set(instance, this.factoryBeanInstanceCache.get(autowiredBeanName).getWrappedInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }

    private Object instantiateBean(String beanName, MyBeanDefinition beanDefinition) {
        String className = beanDefinition.getBeanClassName();
        Object instance = null;
        try {
            Class<?> clazz = Class.forName(className);
            instance = clazz.newInstance();
            // TODO 如果是代理对象，就会触发AOP的逻辑


            this.factoryBeanObjectCache.put(beanName, instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    public int getBeanDefinitionCount() {
        return this.registry.beanDefinitionMap.size();
    }

    public String[] getBeanDefinitionNames() {
        return this.registry.beanDefinitionMap.keySet().toArray(new String[0]);
    }
}
